<template>
  <a-collapse ref="collapseRef" v-model:activeKey="activeKey" class="no-select">
    <template #expandIcon="{ isActive }">
      <i class="icon-arrow-right-s-fill iconfont" :style="{ transform: `rotate(${isActive ? 90 : 0}deg)` }"></i>
    </template>
    <a-collapse-panel :key="1" header="数据集*">
      <div class="panel-content" :style="{ height: contentHeight + 'px' }">
        <div class="data-list">
          <div
            v-for="item in dataBucketList"
            :key="item.key"
            class="data-item"
            :class="[item.deleted === 1 && 'deleted']"
            :title="item.title"
          >
            <i :class="['text-color-1', 'iconfont', item.isLeaf ? 'icon-File' : 'icon-folder-3-line']"></i> {{ item.title }}
          </div>
        </div>
      </div>

      <template #extra>
        <a-button v-if="canEdit" type="text" class="icon-only-btn" @click.stop="openSelectDataBucket">
          <i class="iconfont icon-edit-line"></i>
        </a-button>
        <g-select-tree-data
          ref="selectDataBucketRef"
          class="task-select-tree-data"
          type-name="数据集"
          has-modal
          :checked-ids="dataBucketIds"
          :get-tree-data-api="selectTreeDataApi.dataBucketTree"
          :get-collect-tree-data-api="selectTreeDataApi.collectDataBucketTree"
          :get-list-data-api="selectTreeDataApi.searchBucketList"
          :get-collect-list-data-api="selectTreeDataApi.collectSearchBucketList"
          :field-names="{ children: 'children', title: 'name', key: 'id' }"
          @confirm="updateCheckedDataBucketList"
        />
      </template>
    </a-collapse-panel>
    <a-collapse-panel :key="2" header="模型*">
      <div class="panel-content" :style="{ height: contentHeight + 'px' }">
        <div class="data-list">
          <div v-for="item in modelList" :key="item.key" class="data-item" :class="[item.deleted === 1 && 'deleted']" :title="item.title">
            <i :class="['text-color-1', 'iconfont', item.isLeaf ? 'icon-File' : 'icon-folder-3-line']"></i> {{ item.title }}
          </div>
        </div>
      </div>
      <template #extra>
        <a-button v-if="canEdit" type="text" class="icon-only-btn" @click.stop="openSelectModel">
          <i class="iconfont icon-edit-line"></i>
        </a-button>
        <g-select-tree-data
          ref="selectModelRef"
          type-name="模型"
          crumb-first-name="模型库"
          has-modal
          auto-expand-parent
          :checked-ids="modelIds"
          :get-tree-data-api="selectTreeDataApi.modelTree"
          :get-collect-tree-data-api="selectTreeDataApi.collectModelTree"
          :get-list-data-api="selectTreeDataApi.searchModelList"
          :get-collect-list-data-api="selectTreeDataApi.collectSearchModelList"
          :field-names="{ children: 'children', title: 'name', key: 'id' }"
          @confirm="updateCheckedModelList"
        />
      </template>
    </a-collapse-panel>
    <a-collapse-panel :key="3" header="代码*">
      <div class="panel-content" :style="{ height: contentHeight + 'px' }">
        <div v-if="status === 1 || status === 6" class="h-100% fc">
          <a-spin />
        </div>
        <a-tree
          v-else
          auto-expand-parent
          :tree-data="codeTree"
          :selected-keys="codeTreeSelectedKeys"
          :field-names="{ children: 'childList', title: 'name', key: 'path' }"
          @select="selectCodeTree"
        />
      </div>
      <template #extra>
        <a-button v-if="canEdit" type="text" class="icon-only-btn" @click.stop="selectCode"
          ><i class="iconfont icon-edit-line"></i
        ></a-button>
        <input ref="uploadFileRef" type="file" hidden :accept="FILE_ACCEPT.join(',')" @change="changeFile" @click.stop />
      </template>
    </a-collapse-panel>
  </a-collapse>
</template>

<script lang="ts" setup>
  import { useElementSize } from '@vueuse/core'
  import { message } from 'ant-design-vue'
  import { computed, ref, watch } from 'vue'
  import { nextTick } from 'vue'
  import { useRequest } from 'vue-request'

  import GSelectTreeData from '@/components/GSelectTreeData/index.vue'
  import { TreeNode } from '@/components/GSelectTreeData/types'
  import { algoTestApi, selectTreeDataApi } from '@/services'
  import { hasValidExtension } from '@/utils'
  import { countStrToBit } from '@/utils'

  export interface Props {
    canEdit: boolean
    codeEditorValue: string
    status: number
  }

  const props = withDefaults(defineProps<Props>(), {
    canEdit: true,
    codeEditorValue: '',
    status: 0
  })
  const emits = defineEmits(['updateCode'])

  const activeKey = ref<string[]>([])

  const openActiveKey = (key: string) => {
    if (!activeKey.value.includes(key)) {
      activeKey.value.push(key)
    }
  }

  /* 高度计算------------------------------------------------------------------- */
  const panelHeaderHeight = 36 //头部高度
  const collapseRef = ref()
  const { height: containerHeight } = useElementSize(collapseRef)
  const contentHeight = computed(() => {
    const activePanelCount = activeKey.value.length
    if (activePanelCount === 0) {
      return 999
    }
    return (containerHeight.value - panelHeaderHeight * 3) / activePanelCount
  })

  /* 选择模型、选择数据逻辑------------------------------------------------------------------- */
  const selectDataBucketRef = ref<InstanceType<typeof GSelectTreeData>>()
  const selectModelRef = ref<InstanceType<typeof GSelectTreeData>>()

  const dataBucketIds = ref<string[]>([])
  const modelIds = ref<string[]>([])

  const dataBucketList = ref<TreeNode[]>([])
  const modelList = ref<TreeNode[]>([])

  //打开数据集选择弹窗
  const openSelectDataBucket = async () => {
    selectDataBucketRef.value?.open()
    await nextTick()
    dataBucketList.value.forEach(it => {
      selectDataBucketRef.value?.addKey(it)
    })
  }
  //打开模型选择弹窗
  const openSelectModel = async () => {
    selectModelRef.value?.open()
    await nextTick()
    modelList.value.forEach(it => {
      selectModelRef.value?.addKey(it)
    })
  }

  // 切换已选中的数据集列表
  const updateCheckedDataBucketList = (list: TreeNode[], ids: string[]) => {
    dataBucketList.value = list
    dataBucketIds.value = ids
    openActiveKey('1')
  }
  // 切换已选中的模型列表
  const updateCheckedModelList = (list: TreeNode[], ids: string[]) => {
    modelList.value = list
    modelIds.value = ids
    openActiveKey('2')
  }

  /* 选择代码------------------------------------------------------------------- */
  // 上传文件
  const { data: uploadCodeRes, loading: uploadCodeLoading, runAsync: uploadCodeRun } = useRequest(algoTestApi.uploadCode)
  // 文件详情
  const {
    data: codeDetailRes,
    loading: codeDetailLoading,
    runAsync: codeDetailRun
  } = useRequest<ResponseData<string>>(algoTestApi.codeDetail)
  // 修改文件
  const { loading: editCodeLoading, runAsync: editCodeRun } = useRequest<ResponseData<void>>(algoTestApi.editCode)

  const uploadFileRef = ref<HTMLInputElement | null>(null)
  const FILE_ACCEPT = ['.zip']
  const codeTreeSelectedKeys = ref<string[]>([])
  const codeResource = ref('') //整体代码包所在地址
  const codeTree = ref<any[]>([])
  const codeData = computed(() => codeDetailRes.value?.data) // 当前选中的代码文件的初始数据,用来和编辑器的数据做对比

  watch(codeTreeSelectedKeys, async (val, oVal) => {
    if (oVal[0] && codeData.value !== props.codeEditorValue) {
      // 判断是否有修改
      await editCodeRun({
        path: oVal[0],
        newCodeString: props.codeEditorValue
      })
    }
    // 获取新的代码
    await codeDetailRun({ path: val[0] })
    emits('updateCode', codeData.value)
  })

  const selectCodeTree = (selectedKeys: string[], e: any) => {
    if (!selectedKeys.length) {
      return
    }
    if (e.selected === false) {
      return
    }
    if (!hasValidExtension(selectedKeys[0], ['.py'])) {
      return
    }
    codeTreeSelectedKeys.value = selectedKeys
  }

  const selectCode = () => {
    uploadFileRef.value?.click()
  }
  const clearFile = () => {
    uploadFileRef.value!.value = ''
  }

  const uploadCode = async (file: File) => {
    await uploadCodeRun({ file })
    const data = uploadCodeRes.value?.data
    const tree = data.codeTree?.childList || []
    const source = data.url || ''
    const key = [data.mainPath]
    console.log('setCodeTreeAndSource', source, tree, key)

    setCodeTreeAndSource(source, tree, key)
  }

  const setCodeTreeAndSource = (source: string, tree: any[], key: string[]) => {
    codeResource.value = source
    codeTree.value = tree
    codeTreeSelectedKeys.value = key
    openActiveKey('3')
  }

  const changeFile /* 上传文件 */ = async (e: any) => {
    const selectedFile = e.target.files[0] as File
    const fileName = selectedFile.name
    console.log(fileName, 'fileName', fileName.length)
    if (!selectedFile) {
      return
    }
    const isValidFile = hasValidExtension(selectedFile.name, FILE_ACCEPT)
    if (!isValidFile) {
      message.error('文件格式无效')
      clearFile()
      return
    }
    // if (fileName.length > 200) {
    if (countStrToBit(fileName) > 200) {
      message.error('文件名不能超过200个字节')
      clearFile()
      return
    }
    await uploadCode(selectedFile)
    clearFile()
  }

  /* ------------------------------------------------------------------- */
  const pageLoading = computed(() => uploadCodeLoading.value || codeDetailLoading.value || editCodeLoading.value)
  defineExpose({
    pageLoading,
    dataBucketIds,
    modelIds,
    codeResource,
    codeTreeSelectedKeys,
    saveCurrentCode: () =>
      editCodeRun({
        path: codeTreeSelectedKeys.value[0],
        newCodeString: props.codeEditorValue
      }),
    updateCheckedModelList,
    updateCheckedDataBucketList,
    setCodeTreeAndSource
  })
</script>

<style lang="less" scoped>
  .ant-collapse {
    background: #fff;
    border-top: none;
    border-radius: 0;

    :deep(.ant-collapse-header) {
      align-items: center;
      padding: 6px 16px;
      background: rgba(250, 250, 250, 1);

      .icon-arrow-right-s-fill {
        margin-right: 4px;
        font-size: 24px;
        color: #525263;
        transition: all 0.2s;
      }
    }

    :deep(.ant-collapse-content-box) {
      overflow: hidden;
      padding: 0;

      .panel-content {
        overflow: auto;
        padding: 8px 16px;
        background: #fff;
        transition: all 0.2s;
        box-sizing: border-box;

        .data-list {
          .data-item {
            width: 100%;
            color: @text01;
            .elliptical-1();

            & + .data-item {
              margin-top: 10px;
            }

            &.deleted {
              color: @text04;
            }
          }
        }
      }

      .ant-tree-title {
        display: block;
      }
    }
  }

  .task-select-tree-data {
    :deep(.main-box) {
      width: 100%;
    }
  }
</style>
